//
//  SFBattlefield.h
//  
//	
//  Created by snowymydog on 08/06/2010.
//  Copyright LazyDog 2010. All rights reserved.
//

#import "SFBattlefield.h"
#import "LDSprite.h"
#import "LDSpriteLayer.h"
#import "LDSoundController.h"
// #import	"LDText.h"

// 這個look-up table是可以快速查找出兩個侵略者是否直／橫／斜相連
	// 有兩個用途：
	// 第一是檢查兩個被選定的侵略者是否相連
	// 第二是檢查玩家是否還有合法的下一輪攻擊，這一步份使用這個table會有少許笨，因為會做多了很多重覆檢查
	// 但這個小遊戲，performance不是一個問題，仍然不會影響framerate
	const unsigned short connectionTable[20][8] = {
		{1,5,6,99,99,99,99,99},		//0
		{0,2,5,6,7,99,99,99},		//1
		{1,3,6,7,8,99,99,99},		//2
		{2,4,7,8,9,99,99,99},		//3
		{3,8,9,99,99,99,99,99},		//4
		{0,1,16,10,11,99,99,99},	//5
		{0,1,2,5,7,10,11,12},		//6*
		{1,2,3,6,8,11,12,13},	//7
		{2,3,4,7,9,12,13,14},	//8
		{3,4,8,13,14,99,99,99},	//9
		{5,6,11,15,16,99,99,99},	//10
		{5,6,7,10,12,15,16,17},	//11
		{6,7,8,11,13,16,17,18},	//12
		{7,8,9,12,14,17,18,19},	//13
		{8,9,13,18,19,99,99,99},	//14
		{10,11,16,99,99,99,99,99},	//15
		{10,11,12,15,17,99,99,99},	//16
		{11,12,13,16,18,99,99,99},	//17
		{12,13,14,17,19,99,99,99},	//18
		{13,14,18,99,99,99,99,99}	//19
	};

@implementation SFBattlefield

@synthesize cursorX, cursorY;
@synthesize target01, target02;

- (id) init {
	
	int i, j;
	
	if (self = [super init]) {
		// battlefield有20格（5 x 4)
		// 這裡會建立2個look up table，分別儲存著每一格的座標，x及y
		if (self = [super init]) {
			for (j=0, i=20;j<5;j++, i+=56)		// x座標 (20 - 300) (96 - 20) / 56
				gridX[j] = (CGFloat)i;
			for (j=0, i=128;j<4;j++, i+=56)		// y座標 (128 - 352) 130
				gridY[j] = (CGFloat)i;
		}
		
		
	}

	laserSnd = [[LDSoundController alloc] init];
	return self;
	
}

- (void) setInvadersSprite : (LDSpriteLayer *)slayer {
	invadersSeedLayer = slayer;
}

- (void) setCursorSprite : (LDSpriteLayer *)slayer {
	cursorLayer = slayer;
	
	blinkingCursor01 = [cursorLayer spriteAtIndex : 0];
	blinkingCursor02 = [cursorLayer spriteAtIndex : 1];
	highlightCursor01 = [cursorLayer spriteAtIndex : 2];
	highlightCursor02 = [cursorLayer spriteAtIndex : 3];
}

- (void) newLevel : (int) level{
	

	int		invaderGenerateSeed[6];
	int		invadersOfEachType;
	
	LDSprite *tmpSprite, *newSprite;
	
	int i, num, xx, yy;
	
	// 每個level出現的invaders數目
	int enemiesPerLevel[] = {	
		36,36,36,36,36,
		36,36,36,36,36,
		48,48,48,48,48,
		48,48,48,48,48,
		60,60,60,60,60
	};
	
	// 從look up table中找出現在level應該出現的侵略者數目
	// 所有level 25以後的level，全部都是固定60隻侵略者
	// 再以侵略者數量除以6（因為有六種顏色的侵略者，得出每一種侵略者的數目
	if (level > 24) {
		numberOfTotalInvaders = 60;
		invadersOfEachType = 10;		// 60/6所以是10
	}
	else {
		numberOfTotalInvaders = enemiesPerLevel[level];
		invadersOfEachType = numberOfTotalInvaders / 6;
	}
	
	// 設定一個look up table控制每種invader的數目，
	// 每generate一隻，便將對應數量-1，那會可以準確控制每一種invader的數目
	// table中的6格，分別代表6種invaders
	for (i=0;i<6;i++)
		invaderGenerateSeed[i] = invadersOfEachType;

	// 初始化highlightTable，highlightTable是紀錄要被攻擊的侵略者，
	// 整個table會被初始化為NO，而highlightTable使用期間，最多只有兩隻侵略者會被highlight
	for (i=0;i<20;i++)
		highlightTable[i] = NO;
			
	// 將highlightCount設定為0，highlightCount是被highlight侵略者的數目，當達到2時便會正式攻擊
	highlightCount = 0;
	
	// 將兩個cursor設定為off
	blinkingCursor01.drawMe = NO;
	blinkingCursor02.drawMe = NO;
	
	// 開一個新的layer
	battlefieldLayer = [[LDSpriteLayer alloc] init];
	
	// 逐一建立sprite並加入layer
	for (i=0;i < numberOfTotalInvaders;i++) {
		// xx及yy是用來標示battlefield(5wx4h)，20格中的那一格
		xx = i % 5;
		yy = i / 5;
		
		// 這個while loop會產生一個random number，這個random便是下一隻invader的種類
		// 如果這個品種的invader已全部generate了，便會強制再random另一隻，直至有未被generate的invader為止
		while(true) {
			num = (arc4random() % 6);
			if (invaderGenerateSeed[num] != 0)
				break;
		} // while
		
		invaderOnBattlefield[i] = num;		// 將random出的invader種類放入table
		invaderGenerateSeed[num]--;			// 將對應的invader種類 -1

		// make a new sprite
		// 從layer中抽取對應的invader sprite
		tmpSprite = [invadersSeedLayer spriteAtIndex : num];
		newSprite = [[LDSprite alloc] init];
		[newSprite makeSpriteFromSprite : tmpSprite];

		
		// setup animation etc.
		if (i > 19) {						// 第二十隻以後，即battlefield以外的invaders
			[newSprite setStartXY : 320: 296];	// 暫時set在瑩幕左上方
			[newSprite setNowXY : 320 : 296];
			[newSprite setEndXY : 320 : 296];
			[newSprite calcDistantRatio];
//			[newSprite setDrawMe : NO];		// 但不顯示
		}
		else {
			[newSprite setStartXY : gridX[xx] : gridY[yy]];
			[newSprite setNowXY : gridX[xx] : gridY[yy]];
			[newSprite setEndXY : gridX[xx] : gridY[yy]];
			[newSprite calcDistantRatio];
		}
		
		// 將invader加入到圖層
		[battlefieldLayer addSprite : newSprite];

	} // for
	
} // newLevel

- (void) animate {
	[battlefieldLayer animate];
	[cursorLayer animate];
} // animate

// 這個method是接收到touch後開始運作
- (void) attack : (CGPoint) xy {

	int num;
	
	if ([self isInvadersMarching] == YES)
		return;
		
	if (xy.x < 20 || xy.x > 300)		// touch在battlefield以外 
		return;
	if (xy.y < 128 || xy.y > 352)		// touch在battlefield以外 
		return;
		
	// 找出touch在那一隻invader身上
	cursorX = (((int)xy.x) - 20) / 56;
	cursorY = (((int)xy.y) - 128) / 56;
	
	//num是經cursorX及cursorY轉換出來，對應invaderOnBattlefield及highlightTable等的index
	num = cursorX + (cursorY * 5);
	
	// 檢測及處理touch所選中的格子
	[self handleHighlight : num : cursorX : cursorY];

}

- (void) handleHighlight : (int)pos : (int)x : (int)y {
		
	float xx, yy;
	id cursorNow;

	if ( pos >= [battlefieldLayer count])
		return;
			
	[laserSnd playClick01];
	
	// 這是cursor顯示時的座標
	xx = (float)((x*56)+16);
	yy = (float)((y*56)+124);
		
	// highlightCount儲存著現在被highlight了的侵略者數目，只會有0,1,2三種數值
	// 當highlightCount是2時，可以開始檢測侵略者是否被擊落，但不會在這個method處理
	// cursorNow指向是使用blinkingCursor01或blinkingCursor02
	// 沒有任何highlight當然是使用blinkingCursor01，已有一隻被highlight的話就使用blinkingCursor02
	if (highlightCount == 0) {			// 沒有highlight
		cursorNow = blinkingCursor01;
		highlightCount++;
		[highlightCursor01 setStartXY:xx:yy];
		[highlightCursor01 setEndXY:xx:yy];
		[highlightCursor01 setNowXY:xx:yy];
		[highlightCursor01 calcDistantRatio];
		target01 = pos;
	}
	else if (highlightCount == 1) {
		if (highlightTable[pos] == YES) {			// touch在已被highlight的侵略者上
			highlightTable[pos] = NO;				// 那便取消highlight
			[blinkingCursor01 setDrawMe : NO];		// 隱藏blinkingCursor01的顯示
			highlightCount = 0;						// 重設highlightCount回零
			return;
		}
		else {										// touch在一隻沒有highlight的侵略者
			cursorNow = blinkingCursor02;
			highlightCount++;						// highlightCount變成2
			[highlightCursor02 setStartXY:xx:yy];
			[highlightCursor02 setEndXY:xx:yy];
			[highlightCursor02 setNowXY:xx:yy];
			[highlightCursor02 calcDistantRatio];
			target02 = pos;
		}
	}
	
	highlightTable[pos] = YES;						// 將被touch的那一格設定成yes
	
	// 這裡會設定及顯示cursor
	// cursorNow有可能是blinkingCursor01及blinkingCursor02
	[cursorNow setDrawMe:YES];						// 顯示cursor
	[cursorNow setStartXY : xx : yy];
	[cursorNow setNowXY : xx : yy];
	[cursorNow setEndXY : xx : yy];
	[cursorNow calcDistantRatio];
				
	if (highlightCount == 2) {
		[blinkingCursor01 setDrawMe:NO];		// 先將兩個cursor隱藏
		[blinkingCursor02 setDrawMe:NO];
		highlightCount = 0;						// highlightCount重設回零
		if ([self validAttack] == YES) {
			[self moveInvaders];
			[laserSnd playLaser];
		}
	}
	
} // handleHighlight

//- (void)dealloc {
//	[window release];
//	[glView release];
//	AudioServicesDisposeSystemSoundID(alertSoundID);
//	[super dealloc];
//}

- (BOOL) validAttack {
	
	int i;
		
	// 若所瞄準的兩隻侵略者不同種類，便回傳 NO
	if (invaderOnBattlefield[target01] != invaderOnBattlefield[target02]) {
		// 清除整個highlightTable
		memset (highlightTable,NO,sizeof(BOOL)*20);
		return NO;
	}
		
	// 從look-up table找出相連的格子，最多檢測8次
	for (i=0;i<8;i++) {
		// 只要檢測connectionTable，對應row中儲存著數個參數，每個參數代表著合乎規則的相連格子sequence no.
		if (target02 == connectionTable[target01][i]) {
			return YES;
		}
	}
	
	// 清除整個highlightTable
	memset (highlightTable,NO,sizeof(BOOL)*20);

	return NO;

} // validAttack

// 消除兩隻被瞄準的侵略者，並移動其後的侵略者向前，以填補空出的位置
- (void) moveInvaders {

	int i, xx, yy;
	int max;
	int	newIdx;
	id	tmpSprite;
	
	// 這個for loop的工作是消除被瞄準的侵略者及移動其它侵略者補位
	// 主要利用兩個索引變數，i是掃瞄整個array用（包括所有生存及死亡的侵略者），newIdx是指向仍然生存的侵略者用
	max = [battlefieldLayer count];
	newIdx = 0;
	for (i=0;i<max;i++) {
		if (i < 20) {
			if (highlightTable[i] == YES) {
				highlightTable[i] = NO;
				continue;
			}
		}
		invaderOnBattlefield[newIdx] = invaderOnBattlefield[i];
		newIdx++;
	}
	
	numberOfTotalInvaders -= 2;			// 似乎沒甚麼用

	// 從layer中刪除兩隻已死的侵略者
	// 技巧是先刪除後一隻，再刪除先一隻
	// 如果先刪除前一隻，由於後一隻的索引編號向-1，使用原本的編號便會錯誤刪除，甚至引起error
	if (target01 < target02) {
		[battlefieldLayer removeSpriteAtIndex : target02];
		[battlefieldLayer removeSpriteAtIndex : target01];
		i = target01;
	}
	else {
		[battlefieldLayer removeSpriteAtIndex : target01];
		[battlefieldLayer removeSpriteAtIndex : target02];
		i = target02;
	}	

			
	if ([battlefieldLayer count] > 20)
		max = 20;
	else
		max = [battlefieldLayer count];

	for (;i<max;i++) {
		tmpSprite = [battlefieldLayer spriteAtIndex : i];
		xx = i % 5;
		yy = i / 5;
		[tmpSprite setEndXY : gridX[xx] : gridY[yy]];
		[tmpSprite calcDistantRatio];
		[tmpSprite setDrawMe : YES];
	}
	
	if ([battlefieldLayer count] > 18) {
		tmpSprite = [battlefieldLayer spriteAtIndex : 18];
		[tmpSprite setStartXY : 320 : 296];
		[tmpSprite setNowXY : 320 : 296];
		[tmpSprite calcDistantRatio];
		tmpSprite = [battlefieldLayer spriteAtIndex : 19];
		[tmpSprite setStartXY : 376 : 296];
		[tmpSprite setNowXY : 376 : 296];
		[tmpSprite calcDistantRatio];
	}
	
} // moveInvaders

// 查看battlefield上的侵略者是否正在移動中
- (BOOL) isInvadersMarching {
	
	int	i;
	int cnt;
	id 	tmpSprite;
	
	// 取得當前侵略者數目
	cnt = [battlefieldLayer count];
	
	// 逐一檢查每隻侵略者是否行進中
	for (i=0;i<[battlefieldLayer count];i++) {
		tmpSprite = [battlefieldLayer spriteAtIndex: i];	// 抽取layer中的侵略者
		// 當前位置與目標位置不一致，便判定為移動中
		if (([tmpSprite nowX] != [tmpSprite endX]) || ([tmpSprite nowY] != [tmpSprite endY]))
			return YES;
	}
	
	return NO;
	
} // isInvaderMarching

- (BOOL) isSuccess {
	
	if ([battlefieldLayer count] <= 0) {
		return YES;
	}
	return NO;
}
@end
